package mobilesmil.xml.parsing;

import java.util.HashMap;

import mobilesmil.data.SmilAudioResource;
import mobilesmil.data.SmilDataSet;
import mobilesmil.data.SmilImageResource;
import mobilesmil.data.SmilRegion;
import mobilesmil.data.SmilResource;
import mobilesmil.data.SmilTextResource;
import mobilesmil.data.SmilVideoResource;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * {@link DefaultHandler} used by {@link SmilParser} to read SMIL XML tags from XML document and construct a {@link SmilDataSet}.
 * @author Ryan Ware
 *
 */
public class SmilHandler extends DefaultHandler {

	private static final int DEFAULT_PAR_BEGIN = 0;
	private static final int DEFAULT_PAR_END = 0;
	
	private boolean mInSmilTag = false;
	private boolean mInHeadTag = false;
	private boolean mEndHeadTag = false;
	private boolean mInLayoutTag = false;
	private boolean mInBodyTag = false;
	private boolean mInParTag = false;
	private boolean mInTextTag = false;
	private boolean mInImageTag = false;
	private boolean mInAudioTag = false;
	private boolean mInVideoTag = false;
	
	private int mParBeginTime = DEFAULT_PAR_BEGIN;
	private int mParEndTime = DEFAULT_PAR_END;
	
	private SmilDataSet mParsedSmilDataSet = null;
	private SmilResource mParsedSmilResource = null;
	private HashMap<String, SmilRegion> mParsedSmilRegionsByIdMap = new HashMap<String, SmilRegion>();
	     
     public SmilDataSet getParsedData() {
          return mParsedSmilDataSet;
     }
     
     @Override
     public void startDocument() throws SAXException {
          mParsedSmilDataSet = new SmilDataSet();
     }

     @Override
     public void endDocument() throws SAXException {
          // Nothing to do
     }

     @Override
     public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException 
     {
         boolean foundProblem = false;
         String errorMessage = "<" + localName + "> tag cannot be parsed.";
         
         try 
         {
    	  if(localName.equals("smil")) {
              mInSmilTag = true;
          } else if(localName.equals("head")) {
        	  mInHeadTag = true;
          } else if(localName.equals("body")) {
        	  mInBodyTag = true;
          } else if(mInSmilTag)
          {
        	  if(mInHeadTag)
        	  {
        		  if(localName.equals("layout")) {
        			  mInLayoutTag = true;
        		  }
        		  else if(mInLayoutTag)
        		  {
        			  if(localName.equals("region"))
        			  {
        				  // region must have an id
        				  String id = atts.getValue("id");
        				  
        				  // set default value of attributes
        				  int left = 0;
        				  int top = 0;
        				  int height = mParsedSmilDataSet.getCanvasHeight();
        				  int width = mParsedSmilDataSet.getCanvasWidth();
        				  String backgroundColor = mParsedSmilDataSet.getBackgroundColorHexString();
        				  
        				  // get any user-defined values for optional attributes
        				  if(atts.getValue("left") != null && !atts.getValue("left").equalsIgnoreCase("auto"))
        					  left = Integer.parseInt(atts.getValue("left"));
        				  if(atts.getValue("top") != null && !atts.getValue("top").equalsIgnoreCase("auto"))
        					  top = Integer.parseInt(atts.getValue("top"));
        				  if(atts.getValue("height") != null && !atts.getValue("height").equalsIgnoreCase("auto"))
        					  height = Integer.parseInt(atts.getValue("height"));
        				  if(atts.getValue("width") != null && !atts.getValue("width").equalsIgnoreCase("auto"))
        					  width = Integer.parseInt(atts.getValue("width"));
        				  if(atts.getValue("background-color") != null)
        					  backgroundColor = atts.getValue("background-color");
        				  
        				  // construct SmilRegion object
        				  SmilRegion smilRegion = new SmilRegion(id, backgroundColor, top, left, width, height);
        				  mParsedSmilRegionsByIdMap.put(smilRegion.getId(), smilRegion);
        			  } 
        			  else if(localName.equals("root-layout"))
        			  {
        				  if(atts.getValue("background-color") != null)
        					  mParsedSmilDataSet.setBackgroundColor(atts.getValue("background-color"));
        			  }
        			  else
        				  foundProblem = true;
        		  }
        		  else
        			  foundProblem = true;
        	  }
        	  else if(mInBodyTag && mEndHeadTag)
        	  {
        		  if(localName.equals("par")) 
        		  { // get any par begin or end times
        			  mInParTag = true;
        			  if(atts.getValue("begin") != null)
        				  mParBeginTime = Integer.valueOf(atts.getValue("begin"));
        			  if(atts.getValue("end") != null)
        				  mParEndTime = Integer.valueOf(atts.getValue("end"));
        		  }
        		  else if(mInParTag)
        		  { // new resource to construct
        			  String regionId = atts.getValue("region");
        			  String source = atts.getValue("src");
        			  
        			  if(localName.equals("text")) {
        				  mParsedSmilResource = new SmilTextResource(source, mParsedSmilRegionsByIdMap.get(regionId), mParBeginTime, mParEndTime);
        				  mInTextTag = true;
        			  } else if(localName.equals("img")) {
        				  mParsedSmilResource = new SmilImageResource(source, mParsedSmilRegionsByIdMap.get(regionId), mParBeginTime, mParEndTime);
        				  mInImageTag = true;
        			  } else if(localName.equals("audio")) {
        				  mParsedSmilResource = new SmilAudioResource(source, mParsedSmilRegionsByIdMap.get(regionId), mParBeginTime, mParEndTime);
        				  mInAudioTag = true;
        			  } else if(localName.equals("video")) {
        				  mParsedSmilResource = new SmilVideoResource(source, mParsedSmilRegionsByIdMap.get(regionId), mParBeginTime, mParEndTime);
        				  mInVideoTag = true;
        			  }
        			  if(mInTextTag || mInImageTag || mInAudioTag || mInVideoTag)
        			  {
        				  mParsedSmilResource.setType(localName);
        				  if(atts.getValue("begin") != null)
        					  mParsedSmilResource.setBeginTime(mParBeginTime + Integer.parseInt(atts.getValue("begin")));
        				  if(atts.getValue("end") != null)
        					  mParsedSmilResource.setEndTime(mParBeginTime + Integer.parseInt(atts.getValue("end")));
        			  }
        			  else
        				  foundProblem = true;
        		  }
        		  else
        			  foundProblem = true;
        	  }
        	  else
        		  foundProblem = true;
          }
          else
        	  foundProblem = true;
    	  
    	  if(foundProblem)
    		  throw new SAXParseException(errorMessage, null);
         }
         catch (Exception e) {
        	 throw new SAXParseException(errorMessage, null, e);
         }
         
     }

     @Override
     public void endElement(String namespaceURI, String localName, String qName) throws SAXException 
     {
          if(localName.equals("smil")) {
        	  mInSmilTag = false;
          } else if(localName.equals("head")) {
               mInHeadTag = false;
               mEndHeadTag = true;
          } else if(localName.equals("layout")) {
               mInLayoutTag = false;
          } else if(localName.equals("body")) {
               mInBodyTag = false;
          } else if(localName.equals("par")) {
               mInParTag = false;
               mParBeginTime = DEFAULT_PAR_BEGIN;
               mParEndTime = DEFAULT_PAR_END;
          } else if(localName.equals("text") || localName.equals("img") || localName.equals("audio") || localName.equals("video")) {
        	  mParsedSmilDataSet.addResource(mParsedSmilResource);
          }
     }

}
